package net.cs.rm;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Type;
import java.text.DateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map.Entry;

import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import dao.hb.*;
import net.bat.db.BaseDAOImpl;
import net.bat.task.Task;
import net.bat.task.TaskCenter;
import net.bat.upload.uploadServlet;
import net.bat.util.Cfg;
import net.sk.ws.WSket;

public class JSonOut {
	final static int TYPE_NODE_IMAGE =2;
	final static int  TYPE_NODE_MENU=4;
	final static int  TYPE_NODE_RESTAURANT=1;
	public static String PATH_JSON = uploadServlet.getWorkPath();
	final public static String CN_ROOT = "NRestaurant";
	String filter;
	BaseDAOImpl bdi;
	Task task;
	StringBuffer sbuf;
	
	HashMap<Integer,Node> nodeMap = new HashMap<Integer,Node>();
	static JsonSerializer<Date> ser = new JsonSerializer<Date>() {
		  @Override
		  public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext 
		             context) {
		    return src == null ? null : new JsonPrimitive(src.getTime());
		  }
		};
	public JSonOut(String filter,String tid) {
		this.filter = filter;
		this.task = TaskCenter.getTask(tid);
		sbuf = new StringBuffer();
	}
	public String toJSon(boolean bcover) throws Exception{
		Date dt_beg = new Date();
		HashMap<String,NodeCover> map_cover = new HashMap<String,NodeCover>();
		bdi = (BaseDAOImpl) Cfg.getBean("BaseDAOImpl");
		List ls= bdi.find(filter);
		for(int i=0; i<ls.size(); i++){
			//task.setTotal(4);
			//json主节点
			NBase nb = (NBase)ls.get(i);
			task.setTitle(nb.getTitle());
			if(nb.getTnid()!=null){
				nb=(NBase)bdi.loadPO("dao.hb.NBase", nb.getTnid().toString());
			}
			int uid = nb.getUid();
			Node nd = getNode(nb,bcover);
			String language = nb.getLanguage();
			map_cover.put(getOutName(nb.getId(),language), new NodeCover(nd.getMe(),nd.getRels().get("imgs")));
			if(!bcover){
				jsonNode(nd,nb,language);
			}
			//json翻译主节点
			List lstn = bdi.find("select language from NBase where tnid=?",new Object[]{nb.getId()});
			for(int j=0; j<lstn.size(); j++){
				String lang = (String)lstn.get(j);
				Node tnd = langNode(nd,lang);
				map_cover.put(getOutName(nb.getId(),lang), new NodeCover(tnd.getMe(),tnd.getRels().get("imgs")));
				if(!bcover){
					jsonNode(tnd,nb,lang);
				}
			}
			if(bcover){
				jsonCover(map_cover,uid);
			}
			map_cover.clear();
		}
		//json out cover.json
		
		task.setCur(task.getTotal());
		TaskCenter.done(task.getId());
		sbuf.append("time span:"+(new Date().getTime()-dt_beg.getTime()));
		return sbuf.toString();
	}
	private void jsonCover(HashMap map_cover,int uid) throws IOException{
		task.setInfo("json cover");
		//Gson gson = new Gson();
		Gson gson=new GsonBuilder().setPrettyPrinting().registerTypeAdapter(java.util.Date.class, 
	             ser).setDateFormat(DateFormat.LONG).create();
		String fpath =uid+File.separator+"json";
		uploadServlet.makeDir(fpath,PATH_JSON, false);
		String jstr = gson.toJson(map_cover);
		File f = new File(PATH_JSON+fpath+File.separatorChar
				+"cover.json");
		BufferedWriter fbw = new BufferedWriter(new OutputStreamWriter(
				new FileOutputStream(f), "utf-8"));
		
		fbw.write(jstr);
		fbw.close();
		uploadServlet.appendIndex(uid,'U',f);
		sbuf.append(f.getPath()+":"+f.length()+"<br>\n");
	}
	public static String getOutName(int nid,String lang){
		return nid+"_"+lang;
	}
	private void jsonNode(Node nd,NBase nb,String lang) throws IOException{
		Object me = nd.getMe();
		BeanWrapper bw = new BeanWrapperImpl(me);
		//翻译节点取tnid，否则直接取id
		String cn = me.getClass().getSimpleName();
		Object nid = bw.getPropertyValue("nid");
		task.setInfo("json " +cn+ "["+nid+"]."+lang);
		//Gson gson = new Gson();
		Gson gson=new GsonBuilder().setPrettyPrinting().registerTypeAdapter(java.util.Date.class, 
	             ser).setDateFormat(DateFormat.LONG).create();
		int uid = nb.getUid();
		String fpath =uid+File.separator+"json";
		uploadServlet.makeDir(fpath,PATH_JSON, false);
		String jstr = gson.toJson(nd);
		File f = new File(PATH_JSON+fpath+File.separatorChar
				+getOutName(nb.getId(),lang)+".json");
		BufferedWriter fbw = new BufferedWriter(new OutputStreamWriter(
				new FileOutputStream(f), "utf-8"));
		
		fbw.write("Ext.data.JsonP.feedCb("+jstr+");");
		fbw.close();
		uploadServlet.appendIndex(uid,'U',f);
		sbuf.append(f.getPath()+":"+f.length()+"<br>\n");
	}
	private Node getNode(NBase root,boolean bcover){
		Node rn = new Node();
		NRestaurant nr = (NRestaurant)bdi.get("from NRestaurant where nid=? and id=?", new Object[]{root.getId(),root.getVid()});
		rn.setMe(nr);
		HashMap<String,Node[]> rels = new HashMap<String,Node[]>();
		List imgs = bdi.find("select A from NImage A,NBase B where B.pnid=? and A.id = B.vid and A.nid=B.id order by B.ord",new Object[]{root.getId()});
		Node[] n_imgs = new Node[imgs.size()];
		for(int i=0; i<imgs.size(); i++){
			Node n_img = new Node();
			n_img.setMe(imgs.get(i));
			n_imgs[i]=n_img;
		}
		rels.put("imgs", n_imgs);
		rn.setRels(rels);
		if(bcover){
			return rn;
		}
		List mnus = bdi.find("select A from NMenu A,NBase B where B.pnid=? and A.id = B.vid and A.nid=B.id order by B.ord",new Object[]{root.getId()});
		task.setTotal(mnus.size()+1);
		Node[] n_mnus = new Node[mnus.size()];
		for(int i=0; i<mnus.size(); i++){
			NMenu mnu = (NMenu)mnus.get(i);
			task.setInfo(mnu.getTitle());
			Node rm = new Node();
			HashMap<String,Node[]> m_rels = new HashMap<String,Node[]>();
			rm.setMe(mnu);
			List mis = bdi.find("select A from NImage A,NBase B where B.pnid=? and A.id = B.vid and A.nid=B.id order by B.ord",new Object[]{mnu.getId()});
			Node[] n_m_imgs = new Node[mis.size()];
			for(int j=0; j<mis.size(); j++){
				Node n_img = new Node();
				n_img.setMe(mis.get(j));
				n_m_imgs[j]=n_img;
			}
 			m_rels.put("imgs", n_m_imgs);
			rm.setRels(m_rels);
			n_mnus[i] = rm;
			task.setCur(i+1);
		}
		rels.put("mnus", n_mnus);
		return rn;
	}
	//通用的多级关联加载
	private Node langNode(Node nd,String lang){
		//加载多语种
		//加载图片及多语种
		//加载菜品及多语种
		//加载菜品图片
		Node tnd = new Node();
		Object me = nd.getMe();
		task.setInfo(lang+":"+nd.toString());
		BeanWrapper bw = new BeanWrapperImpl(me);
		//翻译节点取tnid，否则直接取id
		boolean btask = false;
		String cn = me.getClass().getSimpleName();
		if(cn.equals(CN_ROOT)){
			btask=true;
		}
		String sql = "select A from "+cn+" A,NBase B where B.tnid=? and A.id=B.vid and A.nid=B.id and B.language=?";
		Object tnd_me = bdi.get(sql, new Object[]{bw.getPropertyValue("nid"),lang});
		tnd.setMe(tnd_me);
		if(nd.getRels()==null){
			return tnd;
		}
		Iterator<Entry<String,Node[]>> iter = nd.getRels().entrySet().iterator(); 
		HashMap<String,Node[]> rels = new HashMap<String,Node[]>();
		while (iter.hasNext()) { 
			Entry<String,Node[]> entry = iter.next(); 
			Node[] clds = entry.getValue(); 
			int len_clds = clds.length;
			Node[] tclds = new Node[clds.length];
			int len_tclds = 0;
			if(btask){
				task.setTotal(clds.length+1);
			}
			for(int i=0; i<clds.length; i++){
				tclds[i]=langNode(clds[i],lang);
				if(btask){
					task.setCur(i+1);
				}
				if(tclds[i].getMe()!=null){
					len_tclds++;
				}
			}
			//todo tcld.me maybe null
			if(len_tclds==len_clds){
				rels.put(entry.getKey(), tclds);
			}else{
				Node[] tcl = new Node[len_tclds];
				int pos=0;
				for(int i=0; i<len_clds; i++){
					if(tclds[i].getMe()!=null){
						tcl[pos]=tclds[i];
						pos++;
					}
				}
				rels.put(entry.getKey(), tcl);
			}
		} 							
		tnd.setRels(rels);
		return tnd;		
	}

}
